/******************************************************************************
     Copyright:: 2020- IBM, Inc

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
  *****************************************************************************/

import React from "react";
import Header from "./Header";
import ReportManagerHeader from "./ReportManagerHeader";
import ReportManagerTable from "./ReportManagerTable"
import Help from "./Help";
import ReportSummary from "./ReportSummary";
import ReportSplash from "./ReportSplash";
import Report, { preprocessReport, IReport, IReportItem, ICheckpoint, IRuleset } from "./Report";
import PanelMessaging from '../util/panelMessaging';
import MultiScanReport from "../xlsxReport/multiScanReport/xlsx/multiScanReport";
import MultiScanData from "./MultiScanData";
import ReportSummaryUtil from '../util/reportSummaryUtil';
import OptionMessaging from "../util/optionMessaging";
import BrowserDetection from "../util/browserDetection";
// import html2canvas from "html2canvas"

import {
    Loading
} from 'carbon-components-react';


// File is generated by report-react build
import { genReport } from './genReport';
import HelpHeader from './HelpHeader';
import { IArchiveDefinition } from '../background/helper/engineCache';

interface IPanelProps {
    layout: "main" | "sub"
}



interface IPanelState {
    listenerRegistered: boolean,
    numScanning: number,
    report: IReport | null,
    filter: string | null,
    tabURL: string,
    prevTabURL: string | null,
    tabId: number,
    tabTitle: string,
    selectedItem?: IReportItem,
    rulesets: IRuleset[] | null,
    selectedCheckpoint?: ICheckpoint,
    learnMore: boolean,
    learnItem: IReportItem | null,
    showIssueTypeFilter: boolean[],
    scanning: boolean,  // true when scan taking place
    firstScan: boolean, // true when first scan of a url
    scanStorage: boolean, // true when scan storing on
    currentStoredScan: string,
    storedScans: {
        actualStoredScan: boolean;  // denotes actual stored scan vs a current scan that is kept when scans are not being stored
        isSelected: boolean; // stored scan is selected in the Datatable
        url: string;
        pageTitle: string;
        dateTime: number | undefined;
        scanLabel: string;
        userScanLabel: string;
        ruleSet: any;
        guidelines: any;
        reportDate: Date;
        violations: any;
        needsReviews: any;
        recommendations: any;
        elementsNoViolations: number;
        elementsNoFailures: number;
        storedScan: string;
        screenShot: string;
        storedScanData: string;
    }[],
    storedScanCount: number, // number of scans stored
    storedScanData: number, // total amount of scan data stored in MB
    reportManager: boolean, // true show report manager, false do not show
    error: string | null,
    archives: IArchiveDefinition[] | null,
    selectedArchive: string | null,
    selectedPolicy: string | null,
    focusedViewFilter: boolean,
    focusedViewText: string
}

export default class DevToolsPanelApp extends React.Component<IPanelProps, IPanelState> {
    state: IPanelState = {
        listenerRegistered: false,
        numScanning: 0,
        report: null,
        filter: null,
        tabURL: "",
        prevTabURL: "",  // to determine when change url
        tabId: -1,
        tabTitle: "",
        rulesets: null,
        learnMore: false,
        learnItem: null,
        showIssueTypeFilter: [true, false, false, false],
        scanning: false,
        storedScans: [],
        storedScanCount: 0,
        storedScanData: 0,
        reportManager: false, // start with Report Manager not showing
        firstScan: true,
        scanStorage: false,
        currentStoredScan: "", // true if making report for current stored scan (clear on next scan if scanStorage false)
        error: null,
        archives: null,
        selectedArchive: null,
        selectedPolicy: null,
        focusedViewFilter: false,
        focusedViewText: ""
    }

    ignoreNext = false;
    leftPanelRef: React.RefObject<HTMLDivElement>;
    subPanelRef: React.RefObject<HTMLDivElement>;
    ref: any;

    constructor(props: any) {
        super(props);
        this.leftPanelRef = React.createRef();
        this.subPanelRef = React.createRef();
        if (this.props.layout === "sub") {
            this.getCurrentSelectedElement(); // so selected element shows up in switch before first scan
        }
        
        // Only listen to element events on the subpanel
        if (this.props.layout === "sub") {
            chrome.devtools.panels.elements.onSelectionChanged.addListener(() => {
                chrome.devtools.inspectedWindow.eval(`((node) => {
                    let countNode = (node) => { 
                        let count = 0;
                        let findName = node.nodeName;
                        while (node) { 
                            if (node.nodeName === findName) {
                                ++count;
                            }
                            node = node.previousElementSibling; 
                        }
                        return "/"+findName.toLowerCase()+"["+count+"]";
                    }
                    try {
                        let retVal = "";
                        while (node && node.nodeType === 1) {
                            retVal = countNode(node)+retVal;
                            if (node.parentElement) {
                                node = node.parentElement;
                            } else {
                                let parentElement = null;
                                try {
                                    // Check if we're in a shadow DOM
                                    if (node.parentNode && node.parentNode.nodeType === 11) {
                                        parentElement = node.parentNode.host;
                                        retVal = "/#document-fragment[1]"+retVal;
                                    } else {
                                        // Check if we're in an iframe
                                        let parentWin = node.ownerDocument.defaultView.parent;
                                        let iframes = parentWin.document.documentElement.querySelectorAll("iframe");
                                        for (const iframe of iframes) {
                                            try {
                                                if (iframe.contentDocument === node.ownerDocument) {
                                                    parentElement = iframe;
                                                    break;
                                                }
                                            } catch (e) {}
                                        }
                                    }
                                } catch (e) {}
                                node = parentElement;
                            }
                        }
                        return retVal;
                    } catch (err) {
                        console.error(err);
                    }
                })($0)`, (result: string) => {
                    // This filter occurred because we selected an element in the elements tab
                    this.onFilter(result);
                    if (this.ignoreNext) {
                        this.ignoreNext = false;
                    }
                });
            });
        }
    }

    async componentDidMount() {
        console.log("componentDidMount");
        var self = this;
        chrome.storage.local.get("OPTIONS", async function (result: any) {
            //pick default archive id from env
            let archiveId = process.env.defaultArchiveId + "";
            const archives = await self.getArchives();
            const validArchive = ((id: string) => id && archives.some((archive:any) => archive.id === id));
            //if default archive id is not good, pick 'latest'
            if (!validArchive(archiveId)){ 
                archiveId = "latest";
            }

            //use archive id if it is in storage,
            if (result.OPTIONS && result.OPTIONS.selected_archive && validArchive(result.OPTIONS.selected_archive.id)) {
                archiveId = result.OPTIONS.selected_archive.id;
            }

            let selectedArchive = archives.filter((archive:any) => archive.id === archiveId)[0];

            let policyId: string = selectedArchive.policies[0].id;
            const validPolicy = ((id: string) => id && selectedArchive.policies.some((policy:any) => policy.id === id));
            if (!validPolicy(policyId)){ 
                policyId = "IBM_Accessibility";
            }

            //use policy id if it is in storage
            if (result.OPTIONS && result.OPTIONS.selected_ruleset && validPolicy(result.OPTIONS.selected_ruleset.id)) {
                policyId = result.OPTIONS.selected_ruleset.id;
            }

            
            // to fix when undocked get tab id using chrome.devtools.inspectedWindow.tabId
            // and get url using chrome.tabs.get via message "TAB_INFO"
            let thisTabId = chrome.devtools.inspectedWindow.tabId;
            let tab = await PanelMessaging.sendToBackground("TAB_INFO", { tabId: thisTabId });
            if (tab.id && tab.url && tab.id && tab.title) {
                let rulesets = await PanelMessaging.sendToBackground("DAP_Rulesets", { tabId: tab.id })

                if (rulesets.error) {
                    self.setError(rulesets);
                    return;
                }

                if (!self.state.listenerRegistered) {
                    PanelMessaging.addListener("TAB_UPDATED", async message => {
                        self.setState({ tabTitle: message.tabTitle }); // added so titles updated
                        if (message.tabId === self.state.tabId && message.status === "loading") {
                            if (message.tabUrl && message.tabUrl != self.state.tabURL) {
                                self.setState({ report: null, tabURL: message.tabUrl });
                            }
                        }
                    });
                    
                    PanelMessaging.addListener("DAP_SCAN_COMPLETE", self.onReport.bind(self));

                    PanelMessaging.sendToBackground("DAP_CACHED", { tabId: tab.id, tabURL: tab.url, origin: self.props.layout })
                }
                if (self.props.layout === "sub") {
                    self.selectElementInElements();
                }
                self.setState({ rulesets: rulesets, listenerRegistered: true, tabURL: tab.url, 
                    tabId: tab.id, tabTitle: tab.title, showIssueTypeFilter: [true, true, true, true], 
                    error: null, archives, selectedArchive: archiveId, selectedPolicy: policyId });
            }
        });
    }

    setError = (data: any) => {

        if (data.error) {
            this.setState({ error: data.error });
        }
    };

    errorHandler = (error: string | null) => {

        if (error && error.indexOf('Cannot access contents of url "file://') != -1) {

            let sub_s = error.substring(error.indexOf("\"") + 1);
            let sub_e = sub_s.substring(0, sub_s.indexOf("\""));

            return (
                <React.Fragment>
                    <p>Can not scan local file: <span style={{ fontWeight: "bold" }}>{sub_e}</span></p>
                    <br />
                    <p>Follow the {" "}
                        <a href={chrome.runtime.getURL("usingAC.html")} target="_blank" rel="noopener noreferred">User Guide</a>
                        {" "}to allow scanning of local .html or .htm files in your browser</p>
                </React.Fragment>
            )
        }

        return;
    }

    async startScan() {
        // console.log("startScan");
        let tabId = this.state.tabId;
        let tabURL = this.state.tabURL;
        if (tabURL !== this.state.prevTabURL) {
            this.setState({firstScan: true});
        }
        this.state.prevTabURL = tabURL;

        if (tabId === -1) {
            // componentDidMount is not done initializing yet
            setTimeout(this.startScan.bind(this), 100);
        } else {
            this.setState({ numScanning: this.state.numScanning + 1, scanning: true });
            try {
                await PanelMessaging.sendToBackground("DAP_SCAN", { tabId: tabId, tabURL:  tabURL, origin: this.props.layout})
            } catch (err) {
                console.error(err);
            }
        }
    }

    collapseAll() {
        // if (this.state.report) {
        //     this.state.report.filterstamp = new Date().getTime();
        //     this.setState({ filter: null, report: preprocessReport(this.state.report, null, false), selectedItem: undefined, selectedCheckpoint: undefined });
        // }
        this.setState({firstScan: true});
        this.startScan();
    }

    async onReport(message: any): Promise<any> {
        try {
            if( BrowserDetection.isChrome() && !message.tabURL.startsWith("file:")){
                let blob_url = message.blob_url;
                let blob = await fetch(blob_url).then(r => r.blob());
                message = JSON.parse(await blob.text());
            }

            let report = message.report;
            let archives = await this.getArchives();
            
            if (!report) return;

        let check_option = this.getCheckOption(message.archiveId, message.policyId, archives);

            // JCH add itemIdx to report (used to be in message.report)
            report.results.map((result: any, index: any) => {
                result["itemIdx"] = index;
            })
            let tabId = message.tabId;


            if (this.state.tabId === tabId) {
                report.timestamp = new Date().getTime();
                report.filterstamp = new Date().getTime();
                report.option = check_option;

                this.setState({
                    filter: null,
                    numScanning: Math.max(0, this.state.numScanning - 1),
                    report: preprocessReport(report, null, false),
                    selectedItem: undefined
                });
            }
            this.setState({ scanning: false }); // scan done
            // console.log("SCAN DONE");
            
            // Cases for storage
            // Note: if scanStorage false not storing scans, if true storing scans
            // console.log("storedScans.length = ", this.state.storedScans.length, "   scanStorage = ", this.state.scanStorage);

            if (this.state.storedScans.length == 0 && this.state.scanStorage === true) { // NO stored scans and storing scans
                // console.log("choice 1");
                this.storeScan(); // stores first scan - which is both a current and stored scan
            } else if (this.state.storedScans.length == 0 && this.state.scanStorage === false) { // NO stored scans and NOT storing scans
                // console.log("choice 2");
                this.storeScan(); // stores first scan which is a current scan
            } else if (this.state.storedScans.length == 1 && this.state.scanStorage === true) { // one stored scan and storing scans
                // console.log("choice 3");
                if (this.state.storedScans[0].actualStoredScan === false) {
                    this.clearStoredScans(false); // clears the current scan (not an actualStoredScan)
                }
                this.storeScan();
            } else if (this.state.storedScans.length == 1 && this.state.scanStorage === false) { // ONE stored scan and NOT storing scans
                // console.log("choice 4");
                if (this.state.storedScans[this.state.storedScans.length-1].actualStoredScan === false) {
                    this.state.storedScans.pop(); // clears the current scan (that is not an actualStoredScan)
                }
                this.storeScan(); // add current scan
            } else if (this.state.storedScans.length >  1 && this.state.scanStorage === true) { // MULTIPLE stored scans and storing scans
                // console.log("choice 5");
                this.storeScan(); // add new current and stored scan
            } else if (this.state.storedScans.length >  1 && this.state.scanStorage === false) { // MULTIPLE stored scans and NOT storing scans
                // console.log("choice 6");
                if (this.state.storedScans[this.state.storedScans.length-1].actualStoredScan === false) {
                    this.state.storedScans.pop(); // clears the current scan (that is not an actualStoredScan)
                }
                this.storeScan(); // add new current and stored scan
            } 
           
            if (this.props.layout === "sub") {
                if (this.state.firstScan === true && message.origin === this.props.layout) {
                    this.selectElementInElements();
                    this.setState({firstScan: false});
                }
                
                chrome.devtools.inspectedWindow.eval(`((node) => {
                    let countNode = (node) => { 
                        let count = 0;
                        let findName = node.nodeName;
                        while (node) { 
                            if (node.nodeName === findName) {
                                ++count;
                            }
                            node = node.previousElementSibling; 
                        }
                        return "/"+findName.toLowerCase()+"["+count+"]";
                    }
                    let retVal = "";
                    while (node && node.nodeType === 1) {
                        if (node) {
                            retVal = countNode(node)+retVal;
                            if (node.parentElement) {
                                node = node.parentElement;
                            } else {
                                let parentElement = null;
                                try {
                                    // Check if we're in an iframe
                                    let parentWin = node.ownerDocument.defaultView.parent;
                                    let iframes = parentWin.document.documentElement.querySelectorAll("iframe");
                                    for (const iframe of iframes) {
                                        try {
                                            if (iframe.contentDocument === node.ownerDocument) {
                                                parentElement = iframe;
                                                break;
                                            }
                                        } catch (e) {}
                                    }
                                } catch (e) {}
                                node = parentElement;
                            }
                        }
                    }
                    return retVal;
                })($0)`, (result: string) => {
                    // This filter occurred because we selected an element in the elements tab
                    this.onFilter(result);
                    if (this.ignoreNext) {
                        this.ignoreNext = false;
                    }
                });
            }
        } catch (err) {
            console.error(err);
        }
        return true;
    }

    // START - New multi-scan report functions

    async storeScan() {
        // console.log("storeScan");

        // Data to store for Report
        var xlsx_props = {
            report: this.state.report,
            rulesets: this.state.rulesets,
            tabTitle: this.state.tabTitle,
            tabURL: this.state.tabURL
        }

        var report: any = this.state.report;
        var summaryNumbers = ReportSummaryUtil.calcSummary(report);
        var element_no_failures = parseInt((((summaryNumbers[4] - summaryNumbers[3]) / summaryNumbers[4]) * 100).toFixed(0));
        var element_no_violations = parseInt((((summaryNumbers[4] - summaryNumbers[0]) / summaryNumbers[4]) * 100).toFixed(0));

        var violation = report?.counts.total.Violation;
        var needsReview = report?.counts.total["Needs review"];
        var recommendation = report?.counts.total.Recommendation;

        // Keep track of number of stored scans (be sure to adjust when clear scans)
        this.setState(prevState => {
            return {storedScanCount: prevState.storedScanCount + 1}
        });

        // scan label of the current stored scan 
        // the current scan is always stored for the current scan report
        this.setState({ currentStoredScan:  "scan" + this.state.storedScanCount });

        // get only data needed for multi-scan report
        const scanData = MultiScanData.issues_sheet_rows(xlsx_props); 

        // ***** NOT USING LOCAL STORAGE *****
        // console.log("scanData = ",scanData);
        // local storage can only store strings so stringify
        // let currentScanData = JSON.stringify(scanData);
        // console.log("currentScanData = ",currentScanData);

        // console.log("storage space for currentScanData = ", currentScanData.length);

        // Note: here is where the scan is stored so check to see if can be stored
        //       if not turn off state scanStorage, present message that must clear scans
        //       also if they try to turn state scanStorage, again provide message that
        //       must clear scans before can store scans
        // try {
        //     localStorage.setItem("scan" + this.state.storedScanCount +"Data", currentScanData); 
        // } catch (e) {
        //     if (e.name === "QUATA_EXCEEDED_ERR" // Chrome
        //         || e.name === "NS_ERROR_DOM_QUATA_REACHED") { //Firefox/Safari
        //         alert('Quota exceeded!'); //data wasn't successfully saved due to quota exceed so throw an error
        //     }
        // }

        // this.setState(prevState => {
        //     return {storedScanData: prevState.storedScanData + currentScanData.length}
        // });

        // capture screenshot
        let canvas = await PanelMessaging.sendToBackground("DAP_SCREENSHOT", { });
        
        // let promise = new Promise((resolve, reject) => {
        //     //@ts-ignore
        //     chrome.tabs.captureVisibleTab(null, {}, function (image:string) {
        //         resolve(image);
        //         reject(new Error("Capture failed"));
        //     });
        // });

        // let result:any = await promise;
        // canvas = result;
            
        // Data to store for the Scan other than the issues not much data so saved in state memory
        let currentScan = {
            actualStoredScan: this.state.scanStorage ? true : false,
            isSelected: false,
            url: this.state.tabURL,
            pageTitle: this.state.tabTitle,
            dateTime: this.state.report?.timestamp,
            scanLabel: "scan" + this.state.storedScanCount, // is this safe since setState above is async
            userScanLabel: "scan" + this.state.storedScanCount, // this is the visible scan label which may be edited by user
            ruleSet: report.option.deployment.name,
            guidelines: report.option.guideline.name,
            reportDate: new Date(report.timestamp),
            violations: violation,
            needsReviews: needsReview,
            recommendations: recommendation,
            elementsNoViolations: element_no_violations,
            elementsNoFailures: element_no_failures,
            storedScan: "scan" + this.state.storedScanCount,
            screenShot: canvas,
            storedScanData: scanData,
        };

        // Array of stored scans these scans are stored in state memory
        this.setState(({
            storedScans: [...this.state.storedScans, currentScan]
        }));
    }

    storeScanLabel(event:any,i:number) {
        const value = event.target.value;
        
        // let storedScansCopy = this.state.storedScans;
        let storedScansCopy = JSON.parse(JSON.stringify(this.state.storedScans));
        storedScansCopy[i].userScanLabel = value;
        this.setState({storedScans: storedScansCopy});
    }

    setStoredScanCount = () => {
        this.setState({ storedScanCount:  this.clearStoredScans.length });
    }

    clearStoredScans = (fromMenu: boolean) => {
        this.setState({ storedScanCount: 0 }); // reset scan counter
        this.setState({storedScans: []});
        if (fromMenu === true) {
            this.setState({scanStorage: false});
        }
    };

    clearSelectedStoredScans() {
        let storedScansCopy = this.state.storedScans;
        for (let i=0; i<this.state.storedScans.length;i++) {
            storedScansCopy[i].isSelected = false;
        }
        this.setState({storedScans: storedScansCopy});
    }

    actualStoredScansCount = () => {
        let count = 0;
        for (let scan in this.state.storedScans) {
            if (this.state.storedScans[scan].actualStoredScan) {
                count++;
            }
        }
        return count;
    }
    
    startStopScanStoring = () => {
        // flip scanStorage state each time function runs
        if (this.state.scanStorage === true) {
            this.setState({ scanStorage: false });
        } else {
            this.setState({ scanStorage: true });
        }
    }

    // END - New multi-scan report functions

    getArchives = async () => {
        return await OptionMessaging.sendToBackground("OPTIONS", {
          command: "getArchives",
        });
    };

    getCheckOption = (archiveId: string, policyId: string, archives: any) => {
        
        var option = archives.find( (element: any) => element.id === archiveId);
        
        var policy = option.policies;

        var guideline = policy.find( (element: any) => element.id === policyId);

        var ret = {deployment: {id: archiveId, name: option.name}, guideline: {id: policyId, name: guideline.name}}; 

        return ret;
    }

    onFilter(filter: string) {
        if (this.state.report) {
            this.state.report.filterstamp = new Date().getTime();
            this.setState({ filter: filter, report: preprocessReport(this.state.report, filter, !this.ignoreNext) });
        }
        this.getCurrentSelectedElement();
    }

    reportManagerHandler = () => {
        this.setState({ reportManager: true});
    }
    

    reportHandler = async (scanType:string) => { // parameter is scanType with value [current, all, selected]
        if (scanType === "current") {
            if (this.state.report && this.state.rulesets) {
                var reportObj: any = {
                    tabURL: this.state.tabURL,
                    rulesets: this.state.rulesets,
                    report: {
                        timestamp: this.state.report.timestamp,
                        nls: this.state.report.nls,
                        counts: {
                            "total": this.state.report.counts.total,
                            "filtered": this.state.report.counts.filtered
                        },
                        results: []
                    }
                }
                for (const result of this.state.report.results) {
                    reportObj.report.results.push({
                        ruleId: result.ruleId,
                        path: result.path,
                        value: result.value,
                        message: result.message,
                        snippet: result.snippet
                    });
                }
    
                var tabTitle: string = this.state.tabTitle;
                var tabTitleSubString = tabTitle ? tabTitle.substring(0, 50) : "";
                var filename = "Accessibility_Report-" + tabTitleSubString + ".html";
                //replace illegal characters in file name
                filename = filename.replace(/[/\\?%*:|"<>]/g, '-');
    
                var fileContent = "data:text/html;charset=utf-8," + encodeURIComponent(genReport(reportObj));
                var a = document.createElement('a');
                a.href = fileContent;
                a.download = filename;
                var e = document.createEvent('MouseEvents');
                e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                a.dispatchEvent(e);
            }
            this.xlsxReportHandler(scanType);
        } else {
            this.xlsxReportHandler(scanType);
        }
    }

    

    xlsxReportHandler = (scanType:string) => {
        // console.log("xlsxReportHandler");
        //@ts-ignore
        MultiScanReport.multiScanXlsxDownload(this.state.storedScans, scanType, this.state.storedScanCount, this.state.archives);
    }

    

    selectItem(item?: IReportItem, checkpoint?: ICheckpoint) {
        if (this.state.report) {
            if (!item) {
                for (const resultItem of this.state.report.results) {
                    resultItem.selected = false;
                }
                this.setState({ selectedItem: undefined, report: this.state.report });
            } else {
                if (this.props.layout === "main") {
                    if (this.state.rulesets && !checkpoint) {
                        for (const rs of this.state.rulesets) {
                            if (rs.id === "IBM_Accessibility") {
                                for (const cp of rs.checkpoints) {
                                    for (const rule of cp.rules) {
                                        if (rule.id === item.ruleId) {
                                            checkpoint = cp;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    for (const resultItem of this.state.report.results) {
                        resultItem.selected = resultItem.itemIdx === item.itemIdx;
                    }
                    this.setState({ selectedItem: item, report: this.state.report, selectedCheckpoint: checkpoint });
                } else if (this.props.layout === "sub") {
                    if (this.state.report) {
                        for (const resultItem of this.state.report.results) {
                            resultItem.selected = resultItem.path.dom === item.path.dom;
                        }
                        this.setState({ report: this.state.report });
                    }

                    var script =
                    `function lookup(doc, xpath) {
                        if (doc.nodeType === 11) {
                            let selector = ":scope" + xpath.replace(/\\//g, " > ").replace(/\\[(\\d+)\\]/g, ":nth-child($1)");
                            let element = doc.querySelector(selector);
                            return element;
                        } else {
                            let nodes = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null);
                            let element = nodes.iterateNext();
                            if (element) {
                                return element;
                            } else {
                                return null;
                            }
                        }
                    }
                    function selectPath(srcPath) {
                        let doc = document;
                        let element = null;
                        while (srcPath && (srcPath.includes("iframe") || srcPath.includes("#document-fragment"))) {
                            if (srcPath.includes("iframe")) {
                                let parts = srcPath.match(/(.*?iframe\\[\\d+\\])(.*)/);
                                let iframe = lookup(doc, parts[1]);
                                element = iframe || element;
                                if (iframe && iframe.contentDocument) {
                                    doc = iframe.contentDocument;
                                    srcPath = parts[2];
                                } else {
                                    srcPath = null;
                                }
                            } else if (srcPath.includes("#document-fragment")) {
                                let parts = srcPath.match(/(.*?)\\/#document-fragment\\[\\d+\\](.*)/);
                                let fragment = lookup(doc, parts[1]);
                                element = fragment || element;
                                if (fragment && fragment.shadowRoot) {
                                    doc = fragment.shadowRoot;
                                    srcPath = parts[2];
                                } else {
                                    srcPath = null;
                                }
                            }
                        }
                        if (srcPath) {
                            element = lookup(doc, srcPath) || element;
                        }
                        if (element) {
                            inspect(element);
                            var elementRect = element.getBoundingClientRect();
                            var absoluteElementTop = elementRect.top + window.pageYOffset;
                            var middle = absoluteElementTop - 100;
                            element.ownerDocument.defaultView.scrollTo({
                                top: middle,
                                behavior: 'smooth'
                            });
                            return true;
                        }
                        return;
                    }
                    selectPath("${item.path.dom}");
                    `
                    this.ignoreNext = true;
                    chrome.devtools.inspectedWindow.eval(script, function (result, isException) {
                        if (isException) {
                            console.error(isException);
                        }
                        if (!result) {
                            console.log('Could not select element, it may have moved');
                        }
                        // do focus after inspected Window script
                        setTimeout(() => {
                            var button = document.getElementById('backToListView');
                            if (button) {
                                button.focus();
                            }
                        }, 0);
                    });
                    // This filter occurred because we selected an issue in the Accessibility Checker tab
                    this.onFilter(item.path.dom)
                }
            }
        }
    }

    getCurrentSelectedElement() {
        // console.log("getCurrentSelectedElement");
        let mythis = this;
        chrome.devtools.inspectedWindow.eval("$0.tagName", 
            (result:string, isException) => {
                if (isException) {
                    console.error(isException);
                }
                if (!result) {
                    console.log('Could not get selected element');
                }
                // get current element after inspected Window script
                setTimeout(() => {
                    // console.log("result = ",result);
                    mythis.setState({ focusedViewText: "<"+result.toLowerCase()+">"});
                    // console.log("this.state.focusedViewText", this.state.focusedViewText);
                }, 0);
            }
        );
    }

    selectElementInElements () {
        chrome.devtools.inspectedWindow.eval("inspect(document.firstElementChild)", 
            (result:string, isException) => {
                if (isException) {
                    console.error(isException);
                }
                if (!result) {
                    console.log('Could not select element');
                }
                // select element after inspected Window script
                setTimeout(() => {
                    // console.log("selected element");
                }, 0);
            });
    }

    getItem(item: IReportItem) {
        this.setState({ learnMore: true, learnItem: item });
    }

    learnHelp() {
        this.setState({ learnMore: false });
    }

    reportManagerHelp() {
        // clear all selections ?
        this.setState({ reportManager: false });
    }

    showIssueTypeCheckBoxCallback (checked:boolean[]) {
        if (checked[1] == true && checked[2] == true && checked[3] == true) {
            // console.log("All true");
            this.setState({ showIssueTypeFilter: [true, checked[1], checked[2], checked[3]] });
        } else if (checked[1] == false && checked[2] == false && checked[3] == false) {
            // console.log("All false");
            this.setState({ showIssueTypeFilter: [false, checked[1], checked[2], checked[3]] });
        } else {
            // console.log("Mixed");
            this.setState({ showIssueTypeFilter: [false, checked[1], checked[2], checked[3]] });
        }
        // console.log("In showIssueTypeCheckBoxCallback",this.state.showIssueTypeFilter);
    }

    focusedViewCallback (focus:boolean) {
        this.setState({ focusedViewFilter: focus});
    }

    
    render() {
        let error = this.state.error;

        if (error) {
            return this.errorHandler(error);
        }
        else if (this.props.layout === "main") {
            return <React.Fragment>
                <div style={{ display: "flex", height: "100%", maxWidth: "50%" }} className="mainPanel" role="aside" aria-label={!this.state.report?"About IBM Accessibility Checker":this.state.report && !this.state.selectedItem ? "Scan summary" : "Issue help"}>
                    <div ref={this.leftPanelRef} style={{ flex: "1 1 50%", height:"100%", position:"fixed", left:"50%", maxWidth:"50%", backgroundColor: "#f4f4f4", overflowY: this.state.report && this.state.selectedItem ? "scroll" : undefined }}>
                        {!this.state.report && <ReportSplash />}
                        {this.state.report && !this.state.selectedItem && <ReportSummary tabURL={this.state.tabURL} report={this.state.report} />}
                        {this.state.report && this.state.selectedItem && <Help report={this.state.report!} item={this.state.selectedItem} checkpoint={this.state.selectedCheckpoint} />}
                    </div>
                    {this.leftPanelRef.current?.scrollTo(0, 0)}
                    <div style={{ flex: "1 1 50%" }} className="mainPanelRight" role="main" aria-label="IBM Accessibility Assessment">
                        <Header
                            layout={this.props.layout}
                            counts={this.state.report && this.state.report.counts}
                            scanStorage={this.state.scanStorage}
                            storedScans={this.state.storedScans}
                            startScan={this.startScan.bind(this)}
                            clearStoredScans={this.clearStoredScans.bind(this)}
                            reportHandler={this.reportHandler.bind(this)}
                            xlsxReportHandler = {this.xlsxReportHandler}
                            actualStoredScansCount = {this.actualStoredScansCount}
                            startStopScanStoring = {this.startStopScanStoring}
                            reportManagerHandler = {this.reportManagerHandler}
                            collapseAll={this.collapseAll.bind(this)}
                            showIssueTypeCheckBoxCallback={this.showIssueTypeCheckBoxCallback.bind(this)}
                            dataFromParent = {this.state.showIssueTypeFilter}
                            scanning={this.state.scanning}
                            archives = {this.state.archives}
                            selectedArchive = {this.state.selectedArchive}
                            selectedPolicy = {this.state.selectedPolicy}
                            focusedViewCallback={this.focusedViewCallback.bind(this)}
                            focusedViewFilter={this.state.focusedViewFilter}
                            focusedViewText={this.state.focusedViewText}
                            getCurrentSelectedElement={this.getCurrentSelectedElement.bind(this)}
                        />
                        <div style={{ marginTop: "8rem", height: "calc(100% - 8rem)" }}>
                            <div role="region" aria-label="issue list" className="issueList">
                                {this.state.numScanning > 0 ? <Loading /> : <></>}
                                {this.state.report && <Report
                                    selectItem={this.selectItem.bind(this)}
                                    rulesets={this.state.rulesets}
                                    report={this.state.report}
                                    getItem={this.getItem.bind(this)}
                                    learnItem={this.state.learnItem}
                                    layout={this.props.layout}
                                    selectedTab="checklist"
                                    tabs={["checklist", "element", "rule"]}
                                    dataFromParent={this.state.showIssueTypeFilter}
                                    focusedViewFilter={this.state.focusedViewFilter}
                                />}
                            </div>
                        </div>
                    </div>  
                </div>
            </React.Fragment>
        } else if (this.props.layout === "sub") {

            return <React.Fragment>
                {/* ok now need three way display for Report Manager so need reportManager state */}
                <div style={{ display: this.state.reportManager && !this.state.learnMore ? "" : "none", height:"100%" }}>
                    <ReportManagerHeader 
                        reportManagerHelp={this.reportManagerHelp.bind(this)} 
                        actualStoredScansCount={this.actualStoredScansCount.bind(this)} 
                        layout={this.props.layout}
                        scanStorage={this.state.scanStorage}>
                    </ReportManagerHeader>
                    {/* Report List and Details */}
                    <ReportManagerTable
                        layout={this.props.layout} 
                        storedScans={this.state.storedScans} 
                        setStoredScanCount={this.setStoredScanCount.bind(this)} 
                        clearSelectedStoredScans={this.clearSelectedStoredScans.bind(this)} 
                        storeScanLabel={this.storeScanLabel.bind(this)} 
                        reportHandler={this.reportHandler.bind(this)}>
                    </ReportManagerTable>
                </div>
                <div style={{ display: this.state.learnMore && !this.state.reportManager ? "" : "none", height:"100%" }}>
                    <HelpHeader learnHelp={this.learnHelp.bind(this)} layout={this.props.layout}></HelpHeader>
                    <div style={{ overflowY: "scroll", height: "100%" }} ref={this.subPanelRef}>
                        <div style={{ marginTop: "72px", height: "calc(100% - 72px)" }}>
                            <div>
                                <div className="subPanel">
                                    {this.state.report && this.state.learnItem && <Help report={this.state.report!} item={this.state.learnItem} checkpoint={this.state.selectedCheckpoint} />}
                                </div>
                            </div>
                        </div>
                    </div>
                    {this.subPanelRef.current?.scrollTo(0, 0)}
                </div>
                <div style={{ display: !this.state.learnMore && !this.state.reportManager ? "" : "none", height:"100%" }}>
                    <Header
                        layout={this.props.layout}
                        counts={this.state.report && this.state.report.counts}
                        scanStorage={this.state.scanStorage}
                        storedScans={this.state.storedScans}
                        startScan={this.startScan.bind(this)}
                        clearStoredScans={this.clearStoredScans.bind(this)}
                        reportHandler={this.reportHandler.bind(this)}
                        xlsxReportHandler = {this.xlsxReportHandler}
                        actualStoredScansCount = {this.actualStoredScansCount}
                        startStopScanStoring = {this.startStopScanStoring}
                        reportManagerHandler = {this.reportManagerHandler}
                        collapseAll={this.collapseAll.bind(this)}
                        showIssueTypeCheckBoxCallback={this.showIssueTypeCheckBoxCallback.bind(this)}
                        dataFromParent = {this.state.showIssueTypeFilter}
                        scanning={this.state.scanning}
                        archives = {this.state.archives}
                        selectedArchive = {this.state.selectedArchive}
                        selectedPolicy = {this.state.selectedPolicy}
                        focusedViewCallback={this.focusedViewCallback.bind(this)}
                        focusedViewFilter={this.state.focusedViewFilter}
                        focusedViewText={this.state.focusedViewText}
                        getCurrentSelectedElement={this.getCurrentSelectedElement.bind(this)}
                    />
                    <div style={{overflowY:"scroll", height:"100%"}}>
                        <div style={{ marginTop: "8rem", height: "calc(100% - 8rem)" }}>
                            <div role="region" aria-label="issue list" className="issueList">
                                {this.state.numScanning > 0 ? <Loading /> : <></>}
                                {this.state.report && <Report
                                    selectItem={this.selectItem.bind(this)}
                                    rulesets={this.state.rulesets}
                                    report={this.state.report}
                                    getItem={this.getItem.bind(this)}
                                    learnItem={this.state.learnItem}
                                    layout={this.props.layout}
                                    selectedTab="element"
                                    tabs={[ "element", "checklist", "rule"]}
                                    dataFromParent={this.state.showIssueTypeFilter}
                                    focusedViewFilter={this.state.focusedViewFilter}
                                />}
                            </div>
                        </div>
                    </div>
                </div>
            </React.Fragment>
        } else {
            return <React.Fragment>ERROR</React.Fragment>
        }
    }
}
